using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;


//TODO 可以将此类作为Static，只做服务器连接，其余业务重新设计到一个单例可挂载的用户类中

public class NettyClient : SingletonMonoBehaviour<NettyClient>
{

    #region 注册登录服务器

    //连接
    private Socket client;

    private string msg;

    private ConnectionState state;

    //是否等待重连
    private bool waitConnection;
    #endregion

    #region UnityFunction unity函数
    private void Awake()
    {
        //当前状态为等待
        this.state = ConnectionState.wait;
        waitConnection = false;
        //永不销毁
        DontDestroyOnLoad(gameObject);
    }

    // Start is called before the first frame update
    void Start()
    {
        ConnectionCilent();
    }

    // Update is called once per frame
    void Update()
    {

        //判断当前状态，后续需调整心跳策略
        if ((state == ConnectionState.fial || state == ConnectionState.wait) && !waitConnection)
        {

            //重连
            StartCoroutine(ResetConnection());
        }


        if (!string.IsNullOrEmpty(msg))
        {
            //Debug.Log("服务器返回消息：" + msg + "\r\n");
            GameData gameData = UnityTools.ToObject<GameData>(msg);
            msg = "";
            if (gameData != null)
            {
                //事件分发
                EventDelivery(gameData);
            }
        }
    }

    #endregion

    #region TCPServer TCP服务

    /// <summary>
    /// 连接服务器
    /// </summary>
    private void ConnectionCilent()
    {
        try
        {
            client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            client.Connect(Settings.IP, Settings.PORT);
            //Debug.Log("尝试连接服务器...");

            //连接成功
            state = ConnectionState.success;

            //启动线程监听数据
            Thread threadReceive = new Thread(ReceiveMsg);
            threadReceive.IsBackground = true;
            threadReceive.Start();

            Debug.Log("连接成功...");
        }
        catch
        {
            //连接失败，修改状态
            state = ConnectionState.fial;
            
            Debug.Log("连接失败，重新连接...请稍后");
        }
        finally
        {
            waitConnection = false;
        }
    }

    /// <summary>
    /// 向服务器发送消息
    /// </summary>
    /// <param name="num"></param>
    public void SendMessage(string str)
    {
        //string str = "Hello，我是客户端，你收到了吗" + num;
        byte[] data = System.Text.Encoding.Default.GetBytes(str);
        if (this.state!= ConnectionState.success)
        {
            Debug.Log("和服务器断开链接...请稍后再试。");
            return;
        }
        client.Send(data);
    }

    /// <summary>
    /// 读取数据
    /// </summary>
    private void ReceiveMsg()
    {
        byte[] buffer = new byte[1024 * 1024];
        int len = 0;
        while (true)
        {
            len = client.Receive(buffer);
            //需要详细的解码流程，并转化为GameData
            msg = Encoding.UTF8.GetString(buffer, 0, len);
        }
        

    }

    /// <summary>
    /// 断线重连
    /// </summary>
    /// <returns></returns>
    IEnumerator ResetConnection()
    {
        Debug.Log("尝试重新连接，请等待...");
        waitConnection = true;
        //等待五秒后
        yield return new WaitForSeconds(5f);

        ConnectionCilent();
    }

    #endregion

    #region EventListening 事件监听

    private void OnEnable()
    {
        //注册事件
        
        //登录请求
        EventHandler.LoginRequest += ClientRequest;
        //注册请求
        EventHandler.RegisterRequest += ClientRequest;
    }

    private void OnDisable()
    {
        //删除事件

        //登录请求
        EventHandler.LoginRequest -= ClientRequest;
        //注册
        EventHandler.RegisterRequest -= ClientRequest;
    }

    #endregion

    #region  EventInstance 事件实现

    //具体实现
    private void ClientRequest(GameData data)
    {
        //将数据序列化，并发送请求
        string str=UnityTools.ToJson(data);
        SendMessage(str);
    }
    #endregion

    #region  EventResponse 事件响应

    //通过事件管理器触发事件，这里只做分发
    private void EventDelivery(GameData data)
    {
        //print("分发数据为："+data.ToString());
        //分发
        ResponseManager.Instance.EventDelivery(data);
    }

    #endregion

}
